#pragma once
#include <qobject.h>
#include "Config.h"
#include "Log.h"
#include <qthread.h>
#include <vector>

struct MollacDB : DataBufferBase
{
	MollacDB(size_t size);
	void* data() override;
	void free() override;
private:
	void* data_ptr;
};

struct bufferevent;
struct evconnlistener;
struct event;

class Channel : public QObject
{
	Q_OBJECT
public:
	Channel(const ChannelCreateInfo* i);
	virtual ~Channel() { Logger().info("Channel Destroy"); }
	size_t ReadData(read_buffer_cache& cache);
	void SendData(read_buffer_cache& cache);
	USHORT get_local_port();
	ChannelCreateInfo& get_info();
	CHANNEL_STATE state;
	virtual size_t ReadDataImpl(read_buffer_cache& cache) = 0;
	virtual void SendDataImpl(read_buffer_cache& cache) = 0;
	virtual const char* get_proto_name() = 0;
public slots:
	virtual void start() = 0;
	virtual void stop() = 0;
signals:
	void RecordSendData(sockaddr_in, size_t, std::string);
signals:
	void RecordReadData(sockaddr_in, size_t, std::string);
signals:
	void sig_port_changed(USHORT port);
signals:
	void sig_state_changed(CHANNEL_STATE state);
protected:
	ChannelCreateInfo info;
};

class TCPServerChannel : public Channel
{
	Q_OBJECT
public:
	TCPServerChannel(const ChannelCreateInfo* i);
	~TCPServerChannel() override;
	const char* get_proto_name()override;
	size_t ReadDataImpl(read_buffer_cache& cache) override;
	void SendDataImpl(read_buffer_cache& cache) override;
	void start()override {}
	void stop()override {}
private:
	std::vector<std::pair<bufferevent*, sockaddr_in>> clients;
	std::mutex clients_mutex;
	evconnlistener* listenner;
public:
	void add_client(bufferevent* sub);
	void del_client(bufferevent* sub);
};

class TCPClientChannel : public Channel
{
	Q_OBJECT
public:
	TCPClientChannel(const ChannelCreateInfo* i);
	~TCPClientChannel();
	bool reconnect();
	const char* get_proto_name()override;
	void start()override {}
	void stop()override {}
protected:
	size_t ReadDataImpl(read_buffer_cache& cache) override { return 0; };
	void SendDataImpl(read_buffer_cache& cache) override;
private:
	bufferevent* bev;
	struct event* reconnect_event;
};

class UDPChannel : public Channel
{
	Q_OBJECT
public:
	UDPChannel(const ChannelCreateInfo* i);
	~UDPChannel();
	const char* get_proto_name()override;
	size_t ReadDataImpl(read_buffer_cache& cache) override { return 0; };
	void SendDataImpl(read_buffer_cache& cache) override;
	void start()override;
	void stop()override;
private:
	SOCKET _socket;
	struct event* udp_ev;
};